// Copyright (c) 2010 Omer Goshen
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#ifndef TRANSFORMWIDGET_H
#define TRANSFORMWIDGET_H

#include <map>
#include "MudBath.h"

using namespace Ogre;


/**
 * \class TransformWidget
 * \brief 3D Widget used to translate, scale and rotate objects.
 */
class TransformWidget :
	public Ogre::FrameListener,
	public Ogre::RenderQueueListener,
	public Ogre::RenderTargetListener
{
public:
	enum TransformSpace
	{
		LOCAL,
		WORLD,
		VIEW
	};

	enum Axis
	{
		X_AXIS = 0x001,
		Y_AXIS = 0x010,
		Z_AXIS = 0x100
	};

	typedef std::map<Ogre::Entity*, unsigned int> EntityAxisMap;

	enum Mode
	{
		MOVE,
		SCALE,
		ROTATE
	};

	static TransformWidget* getSingletonPtr();
	static TransformWidget& getInstance();

	static bool isTransforming() { return mTransforming; };
	static void setTransforming(bool b) { mTransforming = b; };

	void setMode(Mode m);
	Mode getMode() { return mMode; }

	void setTransformSpace(TransformSpace ts) { mTS = ts; }
	TransformSpace getTransformSpace() { return mTS; }

//	inline void show() { mNode->setVisible(true, false); }
//	inline void hide() { mNode->setVisible(false, true); }

	inline void show() { mOverlay->show(); }
	inline void hide() { mOverlay->hide(); }

	//{{{ Events
	void onEntityPressed(Ogre::Entity* ent);
	void onAxisPressed(unsigned int a);
	void onReleased();
	void onMouseMove(const OIS::MouseEvent &e);

	bool frameEnded(const FrameEvent& evt);
	bool frameStarted(const FrameEvent& evt);
	bool frameRenderingQueued(const FrameEvent& evt);


	void preViewportUpdate(const Ogre::RenderTargetViewportEvent &evt)
	{
		show();
		mNode->setVisible(true, false);
	}

	void postViewportUpdate(const Ogre::RenderTargetViewportEvent &evt)
	{
		hide();
		mNode->setVisible(false, true);
	}

	void renderQueueStarted(Ogre::uint8 id,const Ogre::String &,bool &)
	{
//		if (id == RENDER_QUEUE_OVERLAY)
		if (id == RENDER_QUEUE_OVERLAY || id == 70 || id == 71)
			Root::getSingleton().getRenderSystem()->clearFrameBuffer(FBT_DEPTH);
	}
	void renderQueueEnded(Ogre::uint8,const Ogre::String &,bool &) {}
	//}}}

	SceneManager* 			mSceneMgr;
	std::vector<Entity*>	mEntities;

	/// TODO: what with all the nodes?
	std::vector<SceneNode*> mMoveNodes;
	std::vector<SceneNode*> mScaleNodes;
	std::vector<SceneNode*> mRotateNodes;
	std::vector<SceneNode*> mLineNodes;

	SceneNode* mLineHelpers;
	SceneNode* mCircleNode;
	ManualObject* mCircle;

	BaseGameObject* mGo;
	GameObjectGroup mGroup;

	// The camera watching this widget
	Camera* mCamera;
	SceneNode* mNode;
	SceneNode* mTransNode;
	Vector3 mTransVec;
	int mActiveAxis;
	unsigned int mAxes;
	Vector3 mOffset;

	MovablePlane* mPlane;
	SceneNode* mPlaneNode;
	Entity* mPlaneEnt;

	Mode 			mMode;
	TransformSpace 	mTS;

	Overlay* mOverlay;

private:
	TransformWidget(SceneManager* sceneMgr);
	~TransformWidget();

	void _setup();
	void _clear();

	void setNodesVisible(const Ogre::String& match, bool visible);
	void setNodesColour(const Ogre::String& match, Vector4 col);

	static EntityAxisMap mEntAxisMap;

protected:
	static TransformWidget* mInstance;
	static bool mInit;
	static bool mTransforming;

};



#endif // TRANSFORMWIDGET_H
